﻿using System.Security.Cryptography;
using System.IO;

namespace ImageEncryptor.Core.Security
{
    #region AesEncryptor
    internal static class AesEncryptor
    {
        #region Constants

        internal const int DEFAULT_ITERATIONS = 0X2710;
        internal const int SALT_SIZE = 0X20;

        #endregion

        #region Methods

        internal static byte[] Encrypt(byte[] data, byte[] pass, byte[] salt)
        {
            using (AesManaged aes = new AesManaged())
            {
                aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
                aes.KeySize = aes.LegalKeySizes[0].MaxSize;
                Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(pass, salt, DEFAULT_ITERATIONS);

                aes.Key = key.GetBytes(aes.KeySize / 8);
                aes.IV = key.GetBytes(aes.BlockSize / 8);
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;

                ICryptoTransform t = aes.CreateEncryptor(aes.Key, aes.IV);

                using (var destinationStream = new MemoryStream())
                using (CryptoStream cs = new CryptoStream(destinationStream, t, CryptoStreamMode.Write))
                {
                    cs.Write(data, 0, data.Length);
                    cs.FlushFinalBlock();
                    return destinationStream.ToArray();
                }
            }
        }

        internal static byte[] Decrypt(byte[] data, byte[] pass, byte[] salt)
        {
            AesManaged aes = new AesManaged();
            aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
            aes.KeySize = aes.LegalKeySizes[0].MaxSize;

            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(pass, salt, DEFAULT_ITERATIONS);

            aes.Key = key.GetBytes(aes.KeySize / 8);
            aes.IV = key.GetBytes(aes.BlockSize / 8);
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            ICryptoTransform t = aes.CreateDecryptor(aes.Key, aes.IV);

            using (var destinationStream = new MemoryStream())
            using (CryptoStream cs = new CryptoStream(destinationStream, t, CryptoStreamMode.Write))
            {
                cs.Write(data, 0, data.Length);
                cs.FlushFinalBlock();
                return destinationStream.ToArray();
            }
        }

        #endregion
        
    }
    #endregion
}
